package com.zz.springboot.handler;

import com.zz.springboot.resp.enums.RespCodeEnum;
import com.zz.springboot.exception.BizException;
import com.zz.springboot.exception.ResourceNotFoundException;
import com.zz.springboot.resp.RespTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.security.auth.Subject;
import java.io.IOException;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


    /**
     * 场景1：处理自定义业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BizException.class)
    public RespTemplate handlerBizException(BizException e) {


        return RespTemplate.error(e);
    }


    /**
     * 场景2：处理系统异常（空指针、数据库连接异常、网络波动等待...）
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public RespTemplate handlerSystemException(Exception e) {

        //这里必须把e打印出来，这样才能看到原始异常
        log.error("系统发生未知异常，请求路径{}", getRequestPath(), e);
        return RespTemplate.error();
    }


    // 辅助方法：获取当前请求路径（需要spring-web依赖）
    private String getRequestPath() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes == null ? "" : attributes.getRequest().getRequestURI();
    }


    /**
     * 场景3：处理参数校验异常（@Valid校验失败）
     *
     * @param e 用@Valid校验请求参数时，参数不合法会抛MethodArgumentNotValidException
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RespTemplate handleValidationException(MethodArgumentNotValidException e) {

        // 提取所有校验失败的字段信息（比如"用户名不能为空"）
        String errorMsg = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining("；"));

        return RespTemplate.error(RespCodeEnum.PARAMS_VERIFY_FAIL);
    }


    /**
     * 场景4："404"资源未发现异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ResourceNotFoundException.class) //也可以直接用@ResponseStatus
    public RespTemplate handleResourceNotFound(ResourceNotFoundException e) {

        return RespTemplate.error(e.errCode, e.getErrMsg());
    }

    /**
     * 场景5：用户名或密码错误导致的登录失败
     *
     * @param e
     * @return
     */
    @ExceptionHandler(AuthenticationException.class)
    public RespTemplate handlerAuthenticationException(AuthenticationException e){
        return RespTemplate.error(RespCodeEnum.USERNAME_OR_PASSWORD_ERROR);
    }

    /**
     * 场景6：处理用户未授权异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(AuthorizationException.class)
    public RespTemplate handlerAuthorizationException(AuthorizationException e){
        log.error("用户未授权：{}",e.getMessage());
        return RespTemplate.error(RespCodeEnum.USER_NOT_AUTHORIZED);
    }

    /**
     * 场景7：处理IO异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(IOException.class)
    public RespTemplate handleIOException(IOException e) {
        log.error("IO异常：", e);
        return RespTemplate.error(RespCodeEnum.PARSE_TXT_FAIL);
    }


}
